home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 001 / pibt40s5.arc / RECEIVX2.MOD < prev    next >
Text File  |  1987-07-18  |  27KB  |  706 lines

  1.  
  2. (*----------------------------------------------------------------------*)
  3.  
  4. BEGIN  (* Receive_Xmodem_File *)
  5.                                    (* Open display window for transfer  *)
  6.    Save_Screen( Saved_Screen );
  7.                                    (* Hide cursor *)
  8.    CursorOff;
  9.                                    (* Get protocol name *)
  10.    CASE Transfer_Protocol OF
  11.       Xmodem_Chk   : Tname := 'Xmodem (Checksum)';
  12.       Xmodem_Crc   : Tname := 'Xmodem (CRC)';
  13.       Telink       : Tname := 'Telink';
  14.       Modem7_Chk   : Tname := 'Modem7 (Checksum)';
  15.       Modem7_CRC   : Tname := 'Modem7 (CRC)';
  16.       Xmodem_1K    : Tname := 'Xmodem 1K';
  17.       Xmodem_1KG   : Tname := 'Xmodem 1K G';
  18.       Ymodem_Batch : Tname := 'Ymodem Batch';
  19.       Ymodem_G     : Tname := 'Ymodem G Batch';
  20.       WXModem      : Tname := 'Windowed XModem';
  21.       SeaLink      : Tname := 'SEALink';
  22.    END (* CASE *);
  23.  
  24.    IF FileName = '' THEN
  25.       Menu_Title := 'Receive file using ' + Tname
  26.    ELSE
  27.       Menu_Title := 'Receive file ' + FileName + ' using ' + Tname;
  28.  
  29.    Draw_Menu_Frame( 15, 10, 78, 22, Menu_Frame_Color, Menu_Title_Color,
  30.                     Menu_Text_Color, Menu_Title );
  31.  
  32.    Write_Log( Menu_Title, FALSE, FALSE );
  33.  
  34.    Window( 16, 11, 77, 21 );
  35.                                    (* Initialize status display information *)
  36.    SOH_Errors     := 0;
  37.    BlockL_Errors  := 0;
  38.    BlockN_Errors  := 0;
  39.    Comple_Errors  := 0;
  40.    TimeOut_Errors := 0;
  41.    Resend_Errors  := 0;
  42.    CRC_Errors     := 0;
  43.    Display_Time   := FALSE;
  44.    Dup_Block      := FALSE;
  45.  
  46.    Initialize_Receive_Display;
  47.                                    (* Current sector = 0 *)
  48.    Sector_Number  := 0;
  49.    Sector_Count   := 0;
  50.    Sector_Prev    := 0;
  51.    Sector_Length  := 128;
  52.                                    (* Overall error count = 0 *)
  53.    Error_Count    := 0;
  54.                                    (* CRC, WXModem tries *)
  55.    CRC_Tries      := 0;
  56.    WXM_Tries      := 0;
  57.                                    (* How long to wait for SOH *)
  58.  
  59.    SOH_Time       := Xmodem_Block_Wait;
  60.  
  61.                                    (* Assume file size not sent *)
  62.    Truncate_File  := FALSE;
  63.                                    (* Assume file size, date not sent *)
  64.    RFile_Size     := 0.0;
  65.    RFile_Size_2   := 0.0;
  66.    RFile_Date     := 0.0;
  67.    File_Date      := 0;
  68.    File_Time      := 0;
  69.                                    (* Figure if ACKs to be handled *)
  70.  
  71.    Do_ACKs        := ( Transfer_Protocol <> Ymodem_G   ) AND
  72.                      ( Transfer_Protocol <> Xmodem_1KG );
  73.  
  74.                                    (* Note if WXModem or SeaLink used *)
  75.  
  76.    Do_WXmodem     := ( Transfer_Protocol = WXModem );
  77.    Do_SeaLink     := ( Transfer_Protocol = SeaLink );
  78.  
  79.                                    (* Assume file name not sent *)
  80.    RFile_Name     := '';
  81.                                    (* Assume transfer fails *)
  82.    OK_Transfer    := FALSE;
  83.                                    (* Assume block 0 not found *)
  84.    Block_Zero     := FALSE;
  85.                                    (* Starting time  *)
  86.    Start_Time     := TimeOfDay;
  87.                                    (* User intervention flag *)
  88.    Alt_R_Pressed  := FALSE;
  89.                                    (* Serious error flag     *)
  90.    Stop_Receive   := FALSE;
  91.                                    (* Not null file name   *)
  92.    Null_File_Name := FALSE;
  93.                                    (* Allocate buffer if requested   *)
  94.                                    (* otherwise use sector data area *)
  95.                                    (* directly.                      *)
  96.  
  97.    IF ( Max_Write_Buffer > 1024 ) AND
  98.       ( Max_Write_Buffer < MaxBlockAvail ) THEN
  99.       BEGIN
  100.          Buffer_Length  := Max_Write_Buffer;
  101.          Long_Buffer    := TRUE;
  102.          GetMem( Write_Buffer , Buffer_Length );
  103.       END
  104.    ELSE
  105.       BEGIN
  106.          Long_Buffer   := FALSE;
  107.          Buffer_Length := 1024;
  108.          Write_Buffer  := ADDR( Sector_Data );
  109.       END;
  110.                                    (* Determine block starter characters *)
  111.  
  112.    Block_Start_Set := [ ^A, ^B, ^D, ^V, ^X ];
  113.  
  114.                                    (* No blocks being flushed currently  *)
  115.    Flush_Count    := 0;
  116.                                    (* Empty write buffer   *)
  117.    Buffer_Pos     := 0;
  118.                                    (* Open reception file now if possible *)
  119.    RFile_Open     := FALSE;
  120.  
  121.    IF FileName <> '' THEN
  122.       BEGIN
  123.          Open_Receiving_File;
  124.          IF Stop_Receive THEN
  125.             BEGIN
  126.                Cancel_Transfer;
  127.                DELAY( Two_Second_Delay );
  128.                Restore_Screen( Saved_Screen );
  129.                Reset_Global_Colors;
  130.                EXIT;
  131.             END;
  132.       END;
  133.                                    (* Save Xon/Xoff status *)
  134.  
  135.    Save_XonXoff     := Async_Do_XonXoff;
  136.    Async_Do_XonXoff := Do_WXModem;
  137.  
  138.                                    (* Begin XMODEM loop    *)
  139.    REPEAT
  140.                                    (* Reset error flag *)
  141.       Error_Flag := FALSE;
  142.       Dup_Block  := FALSE;
  143.                                    (* Look for SOH     *)
  144.       REPEAT
  145.  
  146.          IF ( ( Sector_Count = 0 ) AND ( WXM_Tries = 0 ) ) THEN
  147.             BEGIN  (* Initial handshake *)
  148.  
  149.                Use_CRC    := Use_CRC    AND ( CRC_Tries < 4 );
  150.                Do_WXModem := Do_WXModem AND ( WXM_Tries < 4 );
  151.  
  152.                                    (* Purge reception      *)
  153.                Async_Purge_Buffer;
  154.                                    (* Indicate XMODEM type *)
  155.  
  156.                IF Do_WXModem THEN
  157.                   BEGIN
  158.                      Async_Send( 'W' );
  159.                      WXM_Tries := SUCC( WXM_Tries );
  160.                   END
  161.                ELSE
  162.                   BEGIN
  163.                      IF ( NOT Do_ACKs ) THEN
  164.                         Async_Send( 'G' )
  165.                      ELSE
  166.                         IF Use_CRC THEN
  167.                            Async_Send( 'C' )
  168.                         ELSE
  169.                            Async_Send( CHR( NAK ) );
  170.                      CRC_Tries := SUCC( CRC_Tries );
  171.                      IF Do_Sealink THEN
  172.                         BEGIN
  173.                            Async_Send( CHR( 1   ) );
  174.                            Async_Send( CHR( 254 ) );
  175.                         END;
  176.                   END;
  177.  
  178.                IF Display_Status THEN
  179.                   BEGIN
  180.  
  181.                      GoToXY( 1 , 8 );
  182.  
  183.                      TextColor( Menu_Text_Color_2 );
  184.  
  185.                      IF ( NOT Use_CRC ) THEN
  186.                         WRITELN(' Checksum errors      :')
  187.                      ELSE
  188.                         WRITELN(' CRC errors           :');
  189.  
  190.                      TextColor( Menu_Text_Color );
  191.  
  192.                   END;
  193.  
  194.             END   (* Initial handshake *);
  195.  
  196.          Wait_For_SOH( SOH_Time, Initial_Ch , Stop_Receive );
  197.  
  198.                                    (* If CAN found, insist on    *)
  199.                                    (* at least two CANs in a row *)
  200.                                    (* before cancelling transfer *)
  201.  
  202.          IF ( Initial_Ch = CAN ) THEN
  203.             Wait_For_SOH( SOH_Time, Initial_Ch , Stop_Receive )
  204.  
  205.                                    (* If EOT and windowing, insist *)
  206.                                    (* on at least two EOTs in a    *)
  207.                                    (* row before halting.          *)
  208.  
  209.          ELSE IF ( ( Initial_Ch = EOT ) AND
  210.                    ( Do_WXModem OR
  211.                      ( Do_SeaLink AND ( Sector_Count > 0 ) ) ) ) THEN
  212.             BEGIN
  213.                Async_Send( CHR( NAK ) );
  214.                Wait_For_SOH( SOH_Time, Initial_Ch , Stop_Receive )
  215.             END
  216.          ELSE IF ( Initial_Ch = TimeOut ) THEN
  217.             BEGIN
  218.                Async_Send( CHR( NAK ) );
  219.                Display_Receive_Error( 'Time out, no SOH');
  220.                TimeOut_Errors := SUCC( TimeOut_Errors );
  221.             END;
  222.                                    (* If WXmodem, leave Xon/Xoff on *)
  223.  
  224.          Async_Do_XonXoff := Do_WXModem;
  225.  
  226.                                    (* Update status display       *)
  227.          IF Display_Status THEN
  228.             Update_Xmodem_Receive_Display;
  229.  
  230.                                    (* Update status line *)
  231.          IF Do_Status_Line THEN
  232.             BEGIN
  233.                Set_Status_Line_Name( Short_Terminal_Name );
  234.                Write_To_Status_Line( Status_Line_Name, 1 );
  235.             END;
  236.  
  237.       UNTIL ( Initial_Ch = SOH                ) OR
  238.             ( Initial_Ch = EOT                ) OR
  239.             ( Initial_Ch = CAN                ) OR
  240.             ( Initial_Ch = SYN                ) OR
  241.             ( Initial_Ch = STX                ) OR
  242.             ( Error_Count > Xmodem_Max_Errors ) OR
  243.             ( Stop_Receive                    );
  244.  
  245.                                    (* Something wrong already -- *)
  246.                                    (* cancel the transfer.       *)
  247.       IF Stop_Receive THEN
  248.          BEGIN
  249.             IF NOT Async_Carrier_Detect THEN
  250.                BEGIN
  251.                   Display_Receive_Error('Carrier dropped.');
  252.                   DELAY( Two_Second_Delay );
  253.                END;
  254.          END
  255.                                    (* Timed out -- no SOH found *)
  256.  
  257.       ELSE IF Initial_Ch = TimeOut THEN
  258.          BEGIN
  259.             Display_Receive_Error( 'Time out, no SOH');
  260.             TimeOut_Errors := SUCC( TimeOut_Errors );
  261.          END
  262.                                    (* SYN found -- possible Telink block *)
  263.                                    (*              or WXModem start      *)
  264.  
  265.       ELSE IF ( ( Initial_Ch = SYN ) AND Do_WXModem ) THEN
  266.          (* Do nothing and skip SYN *)
  267.  
  268.                                    (* SOH found -- start of XMODEM block *)
  269.                                    (* STX found -- start of Ymodem block *)
  270.                                    (* SYN found -- start of Telink block *)
  271.  
  272.       ELSE IF ( Initial_Ch = SOH ) OR
  273.               ( Initial_Ch = SYN ) OR
  274.               ( Initial_Ch = STX ) THEN
  275.          BEGIN (* SOH found *)
  276.                                    (* Pick up sector number *)
  277.  
  278.             IF Initial_Ch = STX THEN
  279.                Sector_Length := 1024
  280.             ELSE
  281.                Sector_Length := 128;
  282.  
  283.             IF Do_WXModem THEN
  284.                WXModem_Receive_With_TimeOut( Ch )
  285.             ELSE
  286.                Async_Receive_With_TimeOut( Xmodem_Char_Wait , Ch );
  287.  
  288.             IF Ch = TimeOut THEN
  289.                BEGIN
  290.                   BlockL_Errors := SUCC( BlockL_Errors );
  291.                   Display_Receive_Error('Short block');
  292.                END;
  293.  
  294.             Sector_Number := Ch;
  295.  
  296.                                    (* Complement of sector number *)
  297.  
  298.             IF Do_WXModem THEN
  299.                WXModem_Receive_With_TimeOut( Ch )
  300.             ELSE
  301.                Async_Receive_With_TimeOut( Xmodem_Char_Wait , Ch );
  302.  
  303.             IF Ch = TimeOut THEN
  304.                BEGIN
  305.                   BlockL_Errors := SUCC( BlockL_Errors );
  306.                   Display_Receive_Error('Short block');
  307.                END;
  308.  
  309.             Sector_Comp := Ch;
  310.  
  311.                                    (* See if they add up properly     *)
  312.  
  313.             IF ( ( Sector_Number + Sector_Comp ) = 255 ) THEN
  314.  
  315.                BEGIN  (* Sector number and complement match *)
  316.  
  317.                   Sector_Prev1 := SUCC( Sector_Prev );
  318.  
  319.                   Block_Zero   := ( Sector_Count  = 0 ) AND
  320.                                   ( Sector_Number = 0 ) AND
  321.                                   ( ( Initial_Ch  = SYN ) OR
  322.                                     ( Transfer_Protocol IN [Xmodem_1K,
  323.                                                             Xmodem_1KG,
  324.                                                             Ymodem_G,
  325.                                                             Ymodem_Batch,
  326.                                                             SeaLink] ) );
  327.  
  328.                   Use_CRC_2 := Use_CRC AND
  329.                                ( NOT ( Block_Zero AND
  330.                                        ( Transfer_Protocol = Telink ) ) );
  331.  
  332.                   IF ( Sector_Number = Sector_Prev1 ) OR Block_Zero THEN
  333.                      BEGIN  (* Correct sector found *)
  334.  
  335.                         IF Receive_Xmodem_Sector( Use_CRC_2 ) THEN
  336.                            IF ( NOT Block_Zero ) THEN
  337.                               BEGIN (* Checksum/CRC OK *)
  338.  
  339.                                  Write_File_Data;
  340.  
  341.                                  Error_Count  := 0;
  342.  
  343.                                  Sector_Count := Sector_Count +
  344.                                                  ( Sector_Length SHR 7 );
  345.  
  346.                                  Sector_Prev := Sector_Number;
  347.  
  348.                                  IF Do_ACKs THEN
  349.                                     BEGIN
  350.                                        Async_Send( CHR( ACK ) );
  351.                                        IF Do_WXModem THEN
  352.                                           Async_Send( CHR( Sector_Number AND 3 ) )
  353.                                        ELSE IF Do_SeaLink THEN
  354.                                           BEGIN
  355.                                              Async_Send( CHR( Sector_Number ) );
  356.                                              Async_Send( CHR( Sector_Comp   ) );
  357.                                           END;
  358.                                     END;
  359.  
  360.                               END   (* Checksum/CRC OK *)
  361.                            ELSE (* Telink/Ymodem/SeaLink block 0 *)
  362.                               BEGIN
  363.  
  364.                                  IF ( Initial_Ch = SYN ) OR
  365.                                     ( Transfer_Protocol = SeaLink ) THEN
  366.                                     Receive_Telink_Header
  367.                                  ELSE IF ( Transfer_Protocol IN [Xmodem_1K,
  368.                                                                  Xmodem_1KG,
  369.                                                                  Ymodem_G,
  370.                                                                  Ymodem_Batch] ) THEN
  371.                                     Receive_Ymodem_Header;
  372.  
  373.                                  IF ( NOT Stop_Receive ) THEN
  374.                                     BEGIN
  375.                                        IF ( NOT Do_ACKs ) THEN
  376.                                           Async_Send( 'G' )
  377.                                        ELSE
  378.                                           Async_Send( CHR( ACK ) );
  379.                                        IF Do_WXModem THEN
  380.                                           Async_Send( CHR( Sector_Number AND 3 ) )
  381.                                        ELSE IF Do_SeaLink THEN
  382.                                           BEGIN
  383.                                              Async_Send( CHR( Sector_Number ) );
  384.                                              Async_Send( CHR( Sector_Comp   ) );
  385.                                           END;
  386.                                        Error_Count := 0;
  387.                                     END;
  388.  
  389.                               END
  390.                         ELSE
  391.                            BEGIN  (* Checksum/CRC error *)
  392.                               CRC_Errors := SUCC( CRC_Errors );
  393.                               IF Use_CRC THEN
  394.                                  Display_Receive_Error('CRC error')
  395.                               ELSE
  396.                                  Display_Receive_Error('Checksum error');
  397.                            END    (* Checksum/CRC error *)
  398.  
  399.                      END  (* Correct sector found *)
  400.  
  401.                   ELSE
  402.                      IF ( Sector_Number = Sector_Prev ) THEN
  403.                         BEGIN  (* Duplicate sector *)
  404.  
  405.                            BS_Flag := Receive_Xmodem_Sector( Use_CRC_2 );
  406.  
  407.                            IF Do_ACKs THEN
  408.                               BEGIN
  409.                                  Async_Send( CHR( ACK ) );
  410.                                  IF Do_WXModem THEN
  411.                                     Async_Send( CHR( Sector_Number AND 3 ) )
  412.                                  ELSE IF Do_SeaLink THEN
  413.                                     BEGIN
  414.                                        Async_Send( CHR( Sector_Number ) );
  415.                                        Async_Send( CHR( Sector_Comp   ) );
  416.                                     END;
  417.                               END;
  418.  
  419.                            Display_Receive_Error('Duplicate block');
  420.  
  421.                            Resend_Errors := SUCC( Resend_Errors );
  422.  
  423.                            Error_Flag := FALSE;
  424.                            Dup_Block  := TRUE;
  425.  
  426.                         END   (* Duplicate sector *)
  427.                      ELSE
  428.                         BEGIN (* Out of sequence sector *)
  429.                            BS_Flag := Receive_Xmodem_Sector( Use_CRC_2 );
  430.                            IF ( Flush_Count > 0 ) THEN
  431.                               BEGIN
  432.                                  Flush_Count := PRED( Flush_Count );
  433.                                  Display_Receive_Error('Re-synchronizing ... ');
  434.                                  Error_Flag  := FALSE;
  435.                               END
  436.                            ELSE
  437.                               BEGIN
  438.                                  Display_Receive_Error('Synchronization error');
  439.                                  BlockN_Errors := SUCC( BlockN_Errors );
  440.                               END;
  441.                         END   (* Out of sequence sector *);
  442.  
  443.                END   (* Sector # and complement match *)
  444.  
  445.             ELSE
  446.                BEGIN (* Sector # and complement do not match *)
  447.                   Display_Receive_Error('Sector number error');
  448.                   Comple_Errors := SUCC( Comple_Errors );
  449.                END   (* Sector # and complement do not match *);
  450.  
  451.          END (* SOH Found *)
  452.       ELSE IF ( Initial_Ch = EOT ) THEN
  453.          BEGIN
  454.             IF ( Do_SeaLink AND ( Sector_Count = 0 ) ) THEN
  455.                Null_File_Name := TRUE;
  456.          END
  457.       ELSE
  458.          BEGIN
  459.             Display_Receive_Error('SOH not found');
  460.             SOH_Errors := SUCC( SOH_Errors );
  461.          END;
  462.                                    (* Process bad blocks here *)
  463.       IF Error_Flag THEN
  464.          BEGIN
  465.                                    (* Increment error count *)
  466.  
  467.             Error_Count := SUCC( Error_Count );
  468.  
  469.                                    (* If not windowing, flush buffer. *)
  470.  
  471.             IF( NOT ( Do_WXmodem OR Do_SeaLink ) ) THEN
  472.                Async_Purge_Buffer;
  473.  
  474.                                    (* Send negative acknowledge to reject *)
  475.                                    (* bad sector.                         *)
  476.  
  477.             Async_Send( CHR( NAK ) );
  478.  
  479.                                    (* If windowing, skip remainder of this *)
  480.                                    (* sector, and set up to skip any left  *)
  481.                                    (* in this window.                      *)
  482.             IF Do_WXModem THEN
  483.                BEGIN
  484.                   Async_Send( CHR( Sector_Number AND 3 ) );
  485.                   Block_Start_Set := [ ^V ];
  486.                   Wait_For_SOH( SOH_Time, Initial_Ch , Stop_Receive );
  487.                   Block_Start_Set := [ ^A, ^B, ^D, ^V, ^X ];
  488.                   Flush_Count := WXmodem_Flush;
  489.                END
  490.             ELSE IF Do_SeaLink THEN
  491.                BEGIN
  492.                   Async_Send( CHR( Sector_Number ) );
  493.                   Async_Send( CHR( 255 - Sector_Number ) );
  494.                   Flush_Count := SEALink_Flush;
  495.                END;
  496.  
  497.          END;
  498.  
  499.       IF Display_Time THEN
  500.          BEGIN
  501.  
  502.             IF ( NOT ( Error_Flag OR Dup_Block ) ) THEN
  503.                BEGIN
  504.  
  505.                   Time_To_Send := Time_To_Send -
  506.                                   Time_Per_Block * ( Sector_Length SHR 7 );
  507.  
  508.                   IF Time_To_Send < 0.0 THEN
  509.                      Time_To_Send := 0.0;
  510.  
  511.                END;
  512.  
  513.          END;
  514.                                    (* Check for keyboard entry    *)
  515.       Check_Keyboard_Input;
  516.                                    (* Update status display       *)
  517.       IF Display_Status THEN
  518.          Update_Xmodem_Receive_Display;
  519.  
  520.    UNTIL ( Initial_Ch = EOT     ) OR
  521.          ( Initial_Ch = CAN     ) OR
  522.          ( Stop_Receive         ) OR
  523.          ( Null_File_Name       ) OR
  524.          ( Error_Count > Xmodem_Max_Errors );
  525.  
  526.                                    (* If serious error or Alt_R hit, *)
  527.                                    (* stop download.                 *)
  528.    IF ( Stop_Receive ) THEN
  529.       BEGIN
  530.  
  531.          Cancel_Transfer;
  532.  
  533.          IF Alt_R_Pressed THEN
  534.             BEGIN
  535.                IF ( NOT Display_Status ) THEN
  536.                   Flip_Display_Status;
  537.                GoToXY( 25 , 10 );
  538.                WRITE('Alt-R hit, receive cancelled.');
  539.                Write_Log('ALT-R hit, receive cancelled.', TRUE, FALSE);
  540.                ClrEol;
  541.             END;
  542.  
  543.       END
  544.                                    (* Null file name -- end of batch *)
  545.    ELSE IF Null_File_Name THEN
  546.       BEGIN
  547.          IF ( NOT Display_Status ) THEN
  548.             Flip_Display_Status;
  549.          GoToXY( 25 , 10 );
  550.          WRITE('Null file name received.');
  551.          Write_Log('Null file name received.', TRUE, FALSE);
  552.          ClrEol;
  553.          OK_Transfer := TRUE;
  554.       END
  555.                                    (* EOT received, error count OK *)
  556.  
  557.    ELSE IF ( ( Initial_Ch = EOT ) AND ( Error_Count <= Xmodem_Max_Errors ) ) THEN
  558.       BEGIN
  559.                                    (* Acknowledge EOT  *)
  560.          Async_Send( CHR( ACK ) );
  561.  
  562.                                    (* Write any remaining data in buffer *)
  563.          IF Buffer_Pos > 0 THEN
  564.             BEGIN
  565.  
  566.                Write_Count := Buffer_Pos;
  567.  
  568.                IF ( ( RFile_Size_2 + Write_Count ) > RFile_Size ) AND
  569.                    Truncate_File THEN
  570.                       Write_Count := TRUNC( RFile_Size - Rfile_Size_2 );
  571.  
  572.                W_Count := Write_Count;
  573.                Err     := Write_File_Handle( XFile_Handle, Write_Buffer^,
  574.                                              Write_Count );
  575.  
  576.                IF ( Err <> 0 ) OR ( Int24Result <> 0 ) OR
  577.                   ( W_Count <> Write_Count ) THEN
  578.                   BEGIN
  579.                      IF ( NOT Display_Status ) THEN
  580.                         Flip_Display_Status;
  581.                      GoToXY( 25 , 10 );
  582.                      WRITE('Error in writing to disk, file may be bad.');
  583.                      ClrEol;
  584.                      DELAY( One_Second_Delay );
  585.                   END;
  586.  
  587.                RFile_Size_2 := RFile_Size_2 + Write_Count;
  588.  
  589.             END;
  590.  
  591.          End_Time       := TimeOfDay;
  592.  
  593.          IF ( NOT Display_Status ) THEN
  594.             Flip_Display_Status;
  595.  
  596.          OK_Transfer := TRUE;
  597.  
  598.          GoToXY( 2 , 10 );
  599.  
  600.          IF RFile_Size > 0.0 THEN
  601.             IF RFile_Size <= RFile_Size_2 THEN
  602.                BEGIN
  603.                   RFile_Size_2 := RFile_Size;
  604.                   WRITE('Reception complete; ');
  605.                END
  606.             ELSE
  607.                BEGIN
  608.                   WRITE('Reception appears incomplete; ');
  609.                   OK_Transfer := FALSE;
  610.                END
  611.          ELSE
  612.             WRITE('Reception complete; ');
  613.  
  614.                                    (* Fix possible wrap around midnight *)
  615.  
  616.          IF End_Time < Start_Time THEN
  617.             End_Time := End_Time + 86400.0;
  618.  
  619.          Effective_Rate := End_Time - Start_Time;
  620.  
  621.          IF ( Effective_Rate = 0.0 ) THEN
  622.             Effective_Rate := 1.0;
  623.  
  624.          Effective_Rate := RFile_Size_2 / Effective_Rate;
  625.  
  626.          WRITE('transfer rate ',Effective_Rate:6:1,' CPS');
  627.          ClrEol;
  628.  
  629.          IF OK_Transfer THEN
  630.             Write_Log('Received file ' + FileName , TRUE , FALSE )
  631.          ELSE
  632.             Write_Log('Received file ' + FileName + ' (appears incomplete)',
  633.                       TRUE , FALSE );
  634.  
  635.          OK_Transfer := TRUE;
  636.  
  637.          STR( Effective_Rate:6:1 , TName );
  638.          Write_Log('Transfer rate was ' + TName + ' CPS' , TRUE, FALSE );
  639.  
  640.       END
  641.    ELSE IF ( Initial_Ch = CAN ) THEN
  642.       BEGIN
  643.          IF ( NOT Display_Status ) THEN
  644.             Flip_Display_Status;
  645.          GoToXY( 25 , 10 );
  646.          WRITE('Transmitter cancelled file transfer.');
  647.          Write_Log('Transmitter cancelled file transfer.', TRUE, FALSE);
  648.          ClrEol;
  649.          Stop_Receive := TRUE;
  650.       END
  651.    ELSE
  652.       BEGIN  (* Too many errors -- cancel transfer *)
  653.  
  654.          Cancel_Transfer;
  655.  
  656.          IF ( NOT Display_Status ) THEN
  657.             Flip_Display_Status;
  658.          GoToXY( 25 , 10 );
  659.          WRITE('Receive cancelled -- too many errors');
  660.          Write_Log('Receive cancelled -- too many errors', TRUE, FALSE);
  661.          ClrEol;
  662.       END;
  663.                                    (* Close transferred file *)
  664.  
  665.    Err := Close_File_Handle( XFile_Handle );
  666.    I   := Int24Result;
  667.                                    (* Set file time and date if Telink *)
  668.                                    (* or Ymodem                        *)
  669.  
  670.    IF ( File_Date <> 0 ) AND Use_Time_Sent THEN
  671.       Set_File_Date_And_Time;
  672.  
  673.                                    (* Delete file if bad               *)
  674.  
  675.    IF ( Evict_Partial_Trans AND ( NOT OK_Transfer ) ) THEN
  676.       BEGIN
  677.          ASSIGN( XFile_Byte , Full_File_Name );
  678.             (*$I-*)
  679.          ERASE( XFile_Byte );
  680.             (*$I+*)
  681.          I := INT24Result;
  682.       END;
  683.  
  684.    DELAY( Two_Second_Delay );
  685.                                    (* Remove download buffer           *)
  686.    IF Long_Buffer THEN
  687.       FREEMEM( Write_Buffer , Buffer_Length );
  688.  
  689.                                    (* Remove XMODEM window             *)
  690.    Restore_Screen( Saved_Screen );
  691.    Reset_Global_Colors;
  692.                                    (* Cursor back on *)
  693.    CursorOn;
  694.                                    (* Restore XON/XOFF status *)
  695.  
  696.    Async_Do_XonXoff := Save_XonXoff;
  697.  
  698.                                    (* Restore status line *)
  699.    IF Do_Status_Line THEN
  700.       BEGIN
  701.          Set_Status_Line_Name( Short_Terminal_Name );
  702.          Write_To_Status_Line( Status_Line_Name, 1 );
  703.       END;
  704.  
  705. END    (* Receive_Xmodem_File *) ;
  706.